﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using SharpSoda.Remote;
using SharpSoda.Storage;

namespace SharpSoda.Server
{
    public class NodeServer
    {
        private string m_StorageName = "";
        private GlobalStorage m_GlobalStorage = null;

        private Dictionary<string, ServerInfo> m_LocalStates = new Dictionary<string, ServerInfo>();
        private Dictionary<string, ILocalServer> m_LocalServers = new Dictionary<string, ILocalServer>();
        private Dictionary<string, IRemoteCaller> m_RemoteServiceCallers = new Dictionary<string, IRemoteCaller>();

        private Timer m_Timer = null;

        public NodeServer(string storageName, int defaultExpiration = 12)
        {
            m_StorageName = storageName;
            m_GlobalStorage = new GlobalStorage(m_StorageName, TimeSpan.FromSeconds(defaultExpiration));
        }

        public ILocalServer AddLocalServer(string svrName, string svrType, ILocalServer server)
        {
            if (m_LocalStates.ContainsKey(svrName)) m_LocalStates.Remove(svrName);
            m_LocalStates.Add(svrName, 
                new ServerInfo() 
                { 
                    ServerAddr = server.GetUri().AbsoluteUri, 
                    ServerName = svrName, 
                    ServerState = 0, 
                    ServerType = svrType
                });

            if (m_LocalServers.ContainsKey(svrName)) m_LocalServers.Remove(svrName);
            m_LocalServers.Add(svrName, server);
            return server;
        }

        public ILocalServer GetLocalServer(string svrName)
        {
            ILocalServer result = null;
            if (m_LocalServers.TryGetValue(svrName, out result)) return result;
            else return null;
        }

        public void AddRemoteServiceCaller(string serviceType, IRemoteCaller caller)
        {
            if (m_RemoteServiceCallers.ContainsKey(serviceType)) m_RemoteServiceCallers.Remove(serviceType);
            m_RemoteServiceCallers.Add(serviceType, caller);
        }

        public IRemoteCaller GetRemoteServiceCaller(string serviceType)
        {
            IRemoteCaller result = null;
            if (m_RemoteServiceCallers.TryGetValue(serviceType, out result)) return result;
            else return null;
        }

        public void StartAutoUpdae(int interval = 1000 * 5)
        {
            if (m_Timer != null) StopAutoUpdae();
            if (m_Timer == null) m_Timer = new Timer(AutoUpdae, this, 200, interval);
        }

        public void StopAutoUpdae()
        {
            if (m_Timer != null)
            {
                m_Timer.Dispose();
                m_Timer = null;
            }
        }

        public void StopLocalServers()
        {
            foreach(var item in m_LocalServers)
            {
                item.Value.Stop();
            }
        }

        private void AutoUpdae(object param)
        {
            foreach (var item in m_LocalStates)
            {
                if (item.Value.ServerState == 0 && m_LocalServers[item.Key].IsWorking())
                {
                    m_GlobalStorage.SetState<ServerInfo>(item.Key, item.Value);
                }
            }

            foreach (var item in m_RemoteServiceCallers)
            {
                Dictionary<string, string> entries = new Dictionary<string,string>();
                List<ServerInfo> states = m_GlobalStorage.GetStates<ServerInfo>("SELECT * FROM `" + m_StorageName + "` WHERE type = '" + item.Key + "'");
                foreach (var svrState in states) entries.Add(svrState.ServerName, svrState.ServerAddr);
                item.Value.Refresh(entries);
            }
        }
    }
}
